package com.markbuikema.juliana32.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map.Entry;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.util.Log;

/**
 * @author mark
 * 
 */
public class KnvbDataManager {

	private static KnvbDataManager instance;
	private static final String API_KEY = "cEdCDjodYVon4Cm";
	private static final String PATH_NAME = "juliana32";
	private static final String INITIALIZE_URL = "http://api.knvbdataservice.nl/api/initialisatie/" + PATH_NAME;
	private static final String REQUEST_URL = "http://api.knvbdataservice.nl/api%s?%sPHPSESSID=%s&hash=%s";
	private static final int STATUS_OK = 1000;
	private String sessionId;
	private boolean initialized;

	private KnvbDataManager() {
	}

	public static KnvbDataManager getInstance() {
		if (instance == null)
			instance = new KnvbDataManager();
		return instance;
	}

	public boolean isInitialized() {
		return initialized;
	}

	public void initialize(final KnvbCallback callback) {
		new AsyncTask<Void, Void, String>() {

			@Override
			protected String doInBackground(Void... params) {

				HttpParams faster = new BasicHttpParams();
				faster.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
				
				HttpClient client = new DefaultHttpClient(faster);
				HttpGet get = new HttpGet(INITIALIZE_URL);
				try {
					HttpResponse response = client.execute(get);
					return EntityUtils.toString(response.getEntity());
				} catch (ClientProtocolException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

				return null;
			}

			protected void onPostExecute(String result) {
				if (result == null) {
					callback.onDataReceived(null);
					return;
				} 
				try {
					JSONObject root = new JSONObject(result);

					boolean ok = root.getInt("errorcode") == STATUS_OK;
					if (ok)
						initialized = true;

					JSONArray list = root.getJSONArray("List");
					JSONObject content = list.getJSONObject(0);

					sessionId = content.getString("PHPSESSID");

					callback.onDataReceived(result);
				} catch (JSONException e) {
					e.printStackTrace();
				}
			}

		}.execute();
	}

	public void request(final String path, final HashMap<String, String> arguments, final KnvbCallback callback) {

		if (!initialized) {
			initialize(new KnvbCallback() {

				@Override
				public void onDataReceived(String result) {
					if (result == null) {
						callback.onDataReceived(null);
					} else {
						request(path, arguments, callback);
					}
				}
			});

			return;
		}

		new AsyncTask<Void, Void, String>() {

			@Override
			protected String doInBackground(Void... params) {

				String argString = "";
				if (arguments != null) {
					StringBuilder b = new StringBuilder();
					for (Entry<String, String> arg : arguments.entrySet()) {
						b.append(arg.getKey());
						b.append("=");
						b.append(arg.getValue());
						b.append("&");
					}
					argString = b.toString();
				}

				HttpParams faster = new BasicHttpParams();
				faster.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
				
				HttpClient client = new DefaultHttpClient(faster);
				String url = String.format(REQUEST_URL, path, argString, sessionId, md5(path));
				HttpGet get = new HttpGet(url);
				try {
					HttpResponse response = client.execute(get);
					return EntityUtils.toString(response.getEntity());
				} catch (ClientProtocolException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

				return null;
			}

			protected void onPostExecute(String result) {
				callback.onDataReceived(result);
			}

		}.execute();
	}

	/**
	 * Returns the hash for the passed url path.
	 * 
	 * @param path
	 *            the path in the url
	 * @return the hash
	 */
	public String md5(String path) {
		String input = API_KEY + "#" + path + "#" + sessionId;
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");

			byte[] hash = md.digest(input.getBytes("UTF-8"));
			StringBuilder sb = new StringBuilder(2 * hash.length);
			for (byte b : hash) {
				sb.append(String.format("%02x", b & 0xff));
			}
			String digest = sb.toString();

			return digest;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

		return null;
	}

	public interface KnvbCallback {
		public void onDataReceived(String json);
	}

}
